//头文件
#include <stdio.h>
#include <sys/types.h> //open write头文件
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h> //strlen 头文件
#include <unistd.h>//access 函数头文件
#include <stdint.h> // for uint8_t
#include <poll.h>


struct pollfd fds[1]; // poll结构体数组
volatile uint8_t statement = 0;
volatile uint8_t KeyNum = 0;
int m = 0;
//gpio从内核空间导出到应用空间
//相当于命令echo 139 > export
int gpio_export(char *argv){
    int fd; //文件描述符
    int len;
    int ret;
    fd = open("/sys/class/gpio/export",O_WRONLY);

    if(fd < 0){
        printf("open /sys/class/gpio/export error\n");
        return -1;
    }

    len = strlen(argv);
    ret = write(fd,argv,len); //写入139
    if(ret < 0){
        printf("write /sys/class/gpio/export error\n");
        return -2;
    }
    close(fd);
}

//取消gpio从内核空间导出到应用空间
//相当于命令echo 139 > unexport
int gpio_unexport(char *argv){
    
    int fd; //文件描述符
    int len;
    int ret;
   fd = open("/sys/class/gpio/unexport",O_WRONLY);

    if(fd < 0){
        printf("open /sys/class/gpio/unexport error\n");
        return -1;
    }
    len = strlen(argv);//计算字符串长度
    ret = write(fd,argv,len); //写入139
    if(ret < 0){
        printf("write /sys/class/gpio/unexport error\n");
        return -2;
    }
    close(fd);
}

//设置gpio,传入两个参数，方向和值
int gpio_ctrl(char *arg, char *val)
{
    int fd; //文件描述符
    int len;
    int ret;
    char gpio_path[100];
    char file_path[100];
    sprintf(gpio_path, "/sys/class/gpio/gpio%s", "122");
    sprintf(file_path,"%s/%s",gpio_path,arg);//获取路径，涉及到参数的传递，这里gpiopath为139
   
    fd = open(file_path,O_WRONLY);

    if(fd < 0){
        printf("open file_path error\n");
        return -1;
    }
    len = strlen(val);
    ret = write(fd,val,len); //写入139
    if(ret < 0){
        printf("write file_path error\n");
        return -2;
    }
    close(fd);
}

int gpio_ctrl2(char *arg, char *val)
{
    int fd; //文件描述符
    int len;
    int ret;
    char gpio_path[100];
    char file_path[100];
    sprintf(gpio_path, "/sys/class/gpio/gpio%s", "104");
    sprintf(file_path,"%s/%s",gpio_path,arg);//获取路径，涉及到参数的传递，这里gpiopath为139
   
    fd = open(file_path,O_WRONLY);

    if(fd < 0){
        printf("open file_path error\n");
        return -1;
    }
    len = strlen(val);
    ret = write(fd,val,len); //写入139
    if(ret < 0){
        printf("write file_path error\n");
        return -2;
    }
    close(fd);
}

int gpio_ctrl3(char *arg, char *val)
{
    int fd; //文件描述符
    int len;
    int ret;
    char gpio_path[100];
    char file_path[100];
    sprintf(gpio_path, "/sys/class/gpio/gpio%s", "115");
    sprintf(file_path,"%s/%s",gpio_path,arg);//获取路径，涉及到参数的传递，这里gpiopath为139
   
    fd = open(file_path,O_WRONLY);

    if(fd < 0){
        printf("open file_path error\n");
        return -1;
    }
    len = strlen(val);
    ret = write(fd,val,len); //写入139
    if(ret < 0){
        printf("write file_path error\n");
        return -2;
    }
    close(fd);
}

int gpio_ctrl4(char *arg, char *val)
{
    int fd; //文件描述符
    int len;
    int ret;
    char gpio_path[100];
    char file_path[100];
    sprintf(gpio_path, "/sys/class/gpio/gpio%s", "121");
    sprintf(file_path,"%s/%s",gpio_path,arg);//获取路径，涉及到参数的传递，这里gpiopath为139
   
    fd = open(file_path,O_WRONLY);

    if(fd < 0){
        printf("open file_path error\n");
        return -1;
    }
    len = strlen(val);
    ret = write(fd,val,len); //写入139
    if(ret < 0){
        printf("write file_path error\n");
        return -2;
    }
    close(fd);
}


//gpio读取高低电平
int gpio_read_value(char *arg){
    int fd; //文件描述符
    int len;
    int ret;
    char file_path[100];
    char gpio_path[100];
    char buf[2];
    sprintf(gpio_path, "/sys/class/gpio/gpio%s", "122");
    sprintf(file_path,"%s/%s",gpio_path,arg);//获取路径，涉及到参数的传递，这里gpiopath为139
    fd = open(file_path,O_RDONLY);

    if(fd < 0){
        printf("read open file_path error\n");
        return -1;
    }
    ret = read(fd,buf,1);
    buf[1]='\0';
    //判断高低电平
 
    if(!strcmp(buf,"1")){

        printf("the value is high\n");
        close(fd);
        return 1;
    }else if(!strcmp(buf,"0")){

        printf("the value is low\n");
        close(fd);
        return 0;

    }
    
    close(fd);
    return -1;

}


void gpioinit(void)
{
    char gpio_path[100];
    sprintf(gpio_path, "/sys/class/gpio/gpio%s", "122");
    if (access((gpio_path),F_OK))//新面孔access函数
    {

        gpio_export("122");//这里的argv[1]代表着传入的gpio引脚
   
    }
   //  else{
    //    gpio_unexport("122");
   // }
    gpio_ctrl("direction", "in");   // 设置为输入模式
    gpio_ctrl("edge", "falling");
}


void gpioinit2(void)
{
    char gpio_path[100];
    sprintf(gpio_path, "/sys/class/gpio/gpio%s", "104");
    if (access((gpio_path),F_OK))//新面孔access函数
    {

        gpio_export("104");//这里的argv[1]代表着传入的gpio引脚
   
    }
    gpio_ctrl2("direction", "in");   // 设置为输入模式
    gpio_ctrl2("edge", "falling");
}

void gpioinit3(void)
{
    char gpio_path[100];
    sprintf(gpio_path, "/sys/class/gpio/gpio%s", "115");
    if (access((gpio_path),F_OK))//新面孔access函数
    {

        gpio_export("115");//这里的argv[1]代表着传入的gpio引脚
   
    }
    gpio_ctrl3("direction", "in");   // 设置为输入模式
    gpio_ctrl3("edge", "falling");
}


void gpioinit4(void)
{
    char gpio_path[100];
    sprintf(gpio_path, "/sys/class/gpio/gpio%s", "121");
    if (access((gpio_path),F_OK))//新面孔access函数
    {

        gpio_export("121");//这里的argv[1]代表着传入的gpio引脚
   
    }
    gpio_ctrl4("direction", "in");   // 设置为输入模式
    gpio_ctrl4("edge", "falling");
}

/*
uint8_t Key_GetNum1(void)
{
    
   if (gpio_read_value("value") == 0) // 只检测有没有按下
    {
        usleep(10000); // 简单去抖（也可以不要）
        if (gpio_read_value("value") == 0)
        {
            usleep(10000); 
            KeyNum = 1; // ✅ 一旦检测到，就置位
        }
    }
    
    return KeyNum;
}
*/

int gpio_interrupt(void)
{
     int fd; //文件描述符
     int len;
     int ret;
     char gpio_path[100];
     char file_path[100];
     char buf[2];
     struct pollfd fds[1]; // poll结构体数组
     sprintf(gpio_path, "/sys/class/gpio/gpio%s", "122");
     sprintf(file_path, "%s/%s", gpio_path, "value"); // 构建文件路径
     fd = open(file_path, O_RDONLY);              // 打开文件
     if (fd < 0)
     {
        printf("open file_path error \n"); // 打开文件失败
        return -1;
     }
     memset((void *)fds, 0, sizeof(fds)); // 清空poll结构体数组
     fds[0].fd = fd;                      // 设置poll结构体的文件描述符
     fds[0].events = POLLPRI;             // 设置poll结构体的事件类型为POLLPRI，表示有紧急数据可读

     read(fd, buf, 2); // 读取文件内容，清除中断事件

     ret = poll(fds, 1, 20); // 调用poll函数等待中断事件发生，阻塞直到事件发生
     if (ret <= 0)
    {
        printf("poll error \n"); // 调用poll失败或超时

        close(fd);
        return -1;
    }
    if(fds[0].revents & POLLPRI)
    {
        lseek(fd, 0, SEEK_SET); // 重新定位文件指针到文件开头
        read(fd, buf, 2);       // 读取文件内容，获取中断事件的值
        buf[1] = '\0';
        KeyNum = 1; // 按键按下
        printf("value is %s\n", buf); // 输出中断事件的值
    }
    close(fd);
    
}

int gpio_interrupt2(void)
{
     int fd; //文件描述符
     int len;
     int ret;
     char gpio_path[100];
     char file_path[100];
     char buf[2];
     struct pollfd fds[1]; // poll结构体数组
     sprintf(gpio_path, "/sys/class/gpio/gpio%s", "104");
     sprintf(file_path, "%s/%s", gpio_path, "value"); // 构建文件路径
     fd = open(file_path, O_RDONLY);              // 打开文件
     if (fd < 0)
     {
        printf("open file_path error \n"); // 打开文件失败
        return -1;
     }
     memset((void *)fds, 0, sizeof(fds)); // 清空poll结构体数组
     fds[0].fd = fd;                      // 设置poll结构体的文件描述符
     fds[0].events = POLLPRI;             // 设置poll结构体的事件类型为POLLPRI，表示有紧急数据可读

     read(fd, buf, 2); // 读取文件内容，清除中断事件

     ret = poll(fds, 1, 20); // 调用poll函数等待中断事件发生，阻塞直到事件发生
     if (ret <= 0)
    {
        printf("poll error \n"); // 调用poll失败或超时

        close(fd);
        return -1;
    }
    if(fds[0].revents & POLLPRI)
    {
        lseek(fd, 0, SEEK_SET); // 重新定位文件指针到文件开头
        read(fd, buf, 2);       // 读取文件内容，获取中断事件的值
        buf[1] = '\0';
        KeyNum = 2; // 按键按下
        printf("value is %s\n", buf); // 输出中断事件的值
    }
    close(fd);
    
}

int gpio_interrupt3(void)
{
     int fd; //文件描述符
     int len;
     int ret;
     char gpio_path[100];
     char file_path[100];
     char buf[2];
     
    struct pollfd fds[1]; // poll结构体数组
     sprintf(gpio_path, "/sys/class/gpio/gpio%s", "115");
     sprintf(file_path, "%s/%s", gpio_path, "value"); // 构建文件路径
     fd = open(file_path, O_RDONLY);              // 打开文件
     if (fd < 0)
     {
        printf("open file_path error \n"); // 打开文件失败
        return -1;
     }
     memset((void *)fds, 0, sizeof(fds)); // 清空poll结构体数组
     fds[0].fd = fd;                      // 设置poll结构体的文件描述符
     fds[0].events = POLLPRI;             // 设置poll结构体的事件类型为POLLPRI，表示有紧急数据可读

     read(fd, buf, 2); // 读取文件内容，清除中断事件

     ret = poll(fds, 1, 20); // 调用poll函数等待中断事件发生，阻塞直到事件发生
     if (ret <= 0)
    {
        printf("poll error \n"); // 调用poll失败或超时

        close(fd);
        return -1;
    }
    if(fds[0].revents & POLLPRI)
    {
        lseek(fd, 0, SEEK_SET); // 重新定位文件指针到文件开头
        read(fd, buf, 2);       // 读取文件内容，获取中断事件的值
        buf[1] = '\0';
        KeyNum = 3; // 按键按下
        printf("value is %s\n", buf); // 输出中断事件的值
    }
    close(fd);
    
}

int gpio_interrupt4(void)
{
     int fd; //文件描述符
     int len;
     int ret;
     char gpio_path[100];
     char file_path[100];
     char buf[2];
      struct pollfd fds[1]; // poll结构体数组
     sprintf(gpio_path, "/sys/class/gpio/gpio%s", "121");
     sprintf(file_path, "%s/%s", gpio_path, "value"); // 构建文件路径
     fd = open(file_path, O_RDONLY);              // 打开文件
     if (fd < 0)
     {
        printf("open file_path error \n"); // 打开文件失败
        return -1;
     }
     memset((void *)fds, 0, sizeof(fds)); // 清空poll结构体数组
     fds[0].fd = fd;                      // 设置poll结构体的文件描述符
     fds[0].events = POLLPRI;             // 设置poll结构体的事件类型为POLLPRI，表示有紧急数据可读

     read(fd, buf, 2); // 读取文件内容，清除中断事件

     ret = poll(fds, 1, 20); // 调用poll函数等待中断事件发生，阻塞直到事件发生
     if (ret <= 0)
    {
        printf("poll error \n"); // 调用poll失败或超时

        close(fd);
        return -1;
    }
    if(fds[0].revents & POLLPRI)
    {
        lseek(fd, 0, SEEK_SET); // 重新定位文件指针到文件开头
        read(fd, buf, 2);       // 读取文件内容，获取中断事件的值
        buf[1] = '\0';
        
        m = m + 1;  // 每次按键按下后，计数器 m 增加 1

        if (m == 1)  // 如果 m 等于 1，表示按下第一次
            statement = 1;  // 将 StateNum 设置为 1

        if (m == 2)  // 如果 m 等于 2，表示按下第二次
            statement = 2;  // 将 StateNum 设置为 2

        if (m == 2)  // 如果 m 等于 2，再次判断
            m = 0;  // 将 m 重置为 0，准备下一次按键计数
       
        printf("value is %s\n", buf); // 输出中断事件的值
    }
    close(fd);
    
}

